import time

from django.shortcuts import render

# Create your views here.
from rest_framework import viewsets, status
from rest_framework.response import Response
from rest_framework.exceptions import AuthenticationFailed
# from rest_framework.pagination import PageNumberPagination
from django.db.models import Q

from datetime import datetime, date, timezone
import traceback

from apps.homepage.models import ZtTestTask, ZtTestRun, ZtUser, ZtProject
from .serializers import ZtTaskDetailSerializer

import time
from functools import wraps

def timing_decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f"Function {func.__name__!r} executed in {(end_time - start_time)*1000:.2f}ms")
        return result
    return wrapper

#判断是否登录
def has_permission(request):

    # session没有token，则未登录
    session_token = request.session.get('token')
    if not session_token:
        return False

    # 如果未传入token，则未登录
    request_token = request.META.get('HTTP_TOKEN')
    if not request_token:
        return False

    #如果都传入，则比对是否一致
    if session_token == request_token:
        return True
    else:
        return False

#所有开发甘特图数据
class GanttListViewSet(viewsets.ViewSet):

    def initial(self, request, *args, **kwargs):
        super(GanttListViewSet, self).initial(request, *args, **kwargs)
        # 检查用户是否登录
        if not has_permission(request):
            # 如果用户未登录，抛出 AuthenticationFailed 异常
            raise AuthenticationFailed({'code': 0, 'msg': '未登录'})

    #甘特图数据
    @timing_decorator
    def gantt(self, request, *args, **kwargs):
        '''
        根据项目id、功能模块id查询对应的需求
        '''
        try:

            #获取参数
            project_id = self.request.query_params.get('project_id', None)
            execution_id = self.request.query_params.get('execution_id', None)

            #如果project_id没有传
            if not project_id:
                return Response({'code': 0, 'msg': '没有携带项目id'}, status=status.HTTP_400_BAD_REQUEST)

            # 搜索条件
            # 初始化一个空的查询集
            query = Q()
            query &= Q(project__id=project_id)  # 根据项目id查询需求
            query &= Q(project__deleted='0')  # 项目不能被删除
            query &= Q(deleted='0')  # 需求不能被删除

            # 如果有执行id
            if execution_id:
                query &= Q(execution=execution_id)  # 对应执行的任务

            test_tasks = ZtTestTask.objects.filter(query).prefetch_related('testRun_task').distinct()

            # _status = '未开始'  #默认为未开始
            # 梳理父子结构
            test_task_dict = {}
            all_names = set()

            # 转换关系
            status_map = {
                'doing': '进行中',
                'done': '已完成',
                'wait': '未开始',
                'blocked': '被阻塞'
            }

            # 转换关系
            case_status_map = {
                '': '未执行',
                'pass': '通过',
                'fail': '失败'
            }

            for test_task in test_tasks:

                # 获取相关测试单的起止日期
                test_task_begin = '' if test_task.begin is None else test_task.begin.strftime('%Y-%m-%d')
                test_task_end = '' if test_task.end is None else test_task.end.strftime('%Y-%m-%d')

                # 关联的测试单的用例
                testRuns = test_task.testRun_task.all()

                cases = []
                for testRun in testRuns:
                    #用例
                    case = testRun.case
                    assignedTo =testRun.assignedTo if testRun.assignedTo else ''

                    #添加到成员中
                    if assignedTo:
                        all_names.add(assignedTo)

                    case_status = case_status_map[case.lastRunResult]

                    # 判断超期状态
                    if test_task.end:
                        # 判断给定的日期时间是否已经超期（即是否在当前日期时间之前）
                        is_overdue = test_task.end < datetime.now(timezone.utc).date()
                        if is_overdue and case_status != '通过':
                            case_status = '超期告警'

                    case_node ={
                        "id": 'case-{}'.format(case.id),
                        'name': case.title,
                        'status': case_status,
                        'begin': test_task_begin,
                        'end': test_task_end,
                        'assignedTo': assignedTo,
                        'type': 'case',
                        'child': [],
                    }

                    cases.append(case_node)

                # 获取成员用户名
                owner = test_task.owner
                members = test_task.members
                persons = set([owner] + members.split(','))

                # 收集所有用户名
                all_names |= persons

                # 修改状态
                test_task.status = status_map[test_task.status]

                # 判断超期状态
                if test_task.end is not None:

                    # 判断给定的日期时间是否已经超期（即是否在当前日期时间之前）
                    is_overdue = test_task.end < datetime.now(timezone.utc).date()
                    if is_overdue and test_task.status != '已完成':
                        test_task.status = '超期告警'

                test_task_node = {
                    "id": 'test_task-{}'.format(test_task.id),
                    'name': test_task.name,
                    'status': test_task.status,
                    'begin': test_task_begin,
                    'end': test_task_end,
                    'assignedTo': persons,
                    'type': 'testTask',
                    'child': cases,
                }

                test_task_dict[test_task.id] = test_task_node

            #查询真实姓名
            name_map = {}
            users = ZtUser.objects.filter(account__in=all_names).values('account', 'realname')
            for user in users:
                name_map[user['account']] = user['realname']

            #处理搜索结果为真实姓名
            for key, value in test_task_dict.items():

                #测试单名字改为真实姓名
                members = value['assignedTo']
                members_realname = [name_map[member] for member in members]
                value['assignedTo'] = ';'.join(members_realname)

                #测试用例改为真实姓名
                for i in range(len(value['child'])):
                    if value['child'][i]['assignedTo']:
                        value['child'][i]['assignedTo'] = name_map[value['child'][i]['assignedTo']]

                test_task_dict[key] = value

            # return Response({'code': 1, 'msg': '获取成功', 'data': list(module_tree.values())})
            return Response({'code': 1, 'msg': '获取成功', 'data': list(test_task_dict.values())})
        except:
            print(traceback.format_exc())
            return Response({'code': 0, 'msg': '获取失败'},status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    # 列表数据
    @timing_decorator
    def list(self, request, *args, **kwargs):
        '''
        根据项目id、功能模块id、需求id查询对应的需求,还可根据名称、状态、指派人进行搜索
        '''
        try:
            # 获取参数
            project_id = self.request.query_params.get('project_id', None)

            _id = self.request.query_params.get('id', None)
            _type = self.request.query_params.get('type', None)

            # 如果project_id没有传
            if not (project_id and _id and _type):
                return Response({'code': 0, 'msg': '缺少参数'}, status=status.HTTP_400_BAD_REQUEST)

            # 获取搜索参数
            filter_name = self.request.query_params.get('name', None)
            filter_status = self.request.query_params.get('status', None)
            filter_assignedTo = self.request.query_params.get('assignedTo', None)

            # 搜索条件
            # 初始化一个空的查询集
            query = Q()
            query &= Q(project__id=project_id)  # 根据项目id查询需求
            query &= Q(project__deleted='0')  # 项目不能被删除
            query &= Q(deleted='0')  # 需求不能被删除
            # query &= Q(id=test_task_id)  # 指定id

            test_tasks = ZtTestTask.objects.filter(query).select_related('execution')\
                .prefetch_related('testRun_task','testRun_task__case__execution').distinct()

            # _status = '未开始'  #默认为未开始
            # 梳理父子结构
            test_task_dict = {}
            team = set()

            # 转换关系
            status_map = {
                'doing': '进行中',
                'done': '已完成',
                'wait': '未开始',
                'blocked': '被阻塞'
            }

            type_map = {
                'feature': '未执行',
                'performance': '性能测试',
                'config': '配置相关',
                'install': '安装部署',
                'security': '安全相关',
                'interface': '接口测试',
                'unit': '单元测试',
                'other': '其他',
                'integrate': '集成测试',
                'system': '系统测试',
                'acceptance': '验收测试',
                'safety': '安全测试',
                '':''
            }

            test_task_type_map = {
                'integrate': '集成测试',
                'system': '系统测试',
                'acceptance': '验收测试',
                'performance': '性能测试',
                'safety': '安全测试',
                'dev': "构建单-研发环境",
                'test': '构建单-仿真环境',
                'prod': "构建单-生产环境",
                '': ''
            }

            # 转换关系
            case_status_map = {
                '': '未执行',
                'pass': '通过',
                'fail': '失败'
            }

            for test_task in test_tasks:

                # 获取相关测试单的起止日期
                test_task_begin = '' if test_task.begin is None else test_task.begin.strftime('%Y-%m-%d')
                test_task_end = '' if test_task.end is None else test_task.end.strftime('%Y-%m-%d')

                # 关联的测试单的用例
                testRuns = test_task.testRun_task.all()

                cases = []
                for testRun in testRuns:
                    # 用例
                    case = testRun.case
                    assignedTo = testRun.assignedTo if testRun.assignedTo else ''

                    # 添加到成员中
                    if assignedTo:
                        team.add(assignedTo)

                    case_status = case_status_map[case.lastRunResult]

                    # 判断超期状态
                    if test_task.end:
                        # 判断给定的日期时间是否已经超期（即是否在当前日期时间之前）
                        is_overdue = test_task.end < datetime.now(timezone.utc).date()
                        if is_overdue and case_status != '通过':
                            case_status = '超期告警'

                    # 获取执行版本
                    execution = case.execution
                    if execution:
                        execution_name = '#{} {}'.format(execution.id, execution.name)
                    else:
                        execution_name = ''

                    # if testRun_task__case__execution
                    case_node = {
                        "id": 'case-{}'.format(case.id),
                        'name': case.title,
                        'status': case_status,
                        'pri': case.pri,
                        'category': type_map[case.type],
                        'begin': test_task_begin,
                        'end': test_task_end,
                        'assignedTo': assignedTo,
                        'execution': execution_name,
                        'type': 'case',
                        'child': [],
                    }

                    cases.append(case_node)

                # 获取成员用户名
                owner = test_task.owner
                members = test_task.members
                persons = set([owner] + members.split(','))

                # 收集所有用户名
                team |= persons

                # 修改状态
                test_task.status = status_map[test_task.status]

                # 使用指派事件和截止时间当做甘特图的起始时间

                if test_task.end is not None:

                    # 判断给定的日期时间是否已经超期（即是否在当前日期时间之前）
                    is_overdue = test_task.end < datetime.now(timezone.utc).date()
                    if is_overdue and test_task.status != '已完成':
                        test_task.status = '超期告警'

                # 将测试类型转换为中文
                test_task_types = test_task.type.split(',')
                test_task.type = ';'.join([test_task_type_map[i] for i in test_task_types])

                # 获取执行版本
                execution = test_task.execution
                if execution:
                    execution_name = '#{} {}'.format(execution.id, execution.name)
                else:
                    execution_name = ''

                test_task_node = {
                    "id": 'test_task-{}'.format(test_task.id),
                    'name': test_task.name,
                    'status': test_task.status,
                    'pri': test_task.pri,
                    'category': test_task.type,
                    'begin': test_task_begin,
                    'end': test_task_end,
                    'assignedTo': persons,
                    'execution': execution_name,
                    'type': 'testTask',
                    'child': cases,
                }

                test_task_dict[test_task.id] = test_task_node

            # 查询真实姓名
            name_map = {}
            users = ZtUser.objects.filter(account__in=team).values('account', 'realname')
            for user in users:
                name_map[user['account']] = user['realname']

            #查询执行id对应的名称
            # execution_map = {}
            # projects = ZtProject.objects.filter(id__in=execution_ls).values('id', 'name')
            # for project in projects:
            #     execution_map[project['id']] = project['name']

            # 处理搜索结果为真实姓名
            for key, value in test_task_dict.items():
                # 测试单名字改为真实姓名
                members = value['assignedTo']
                members_realname = [name_map[member] for member in members]
                value['assignedTo'] = ';'.join(members_realname)

                # 测试用例改为真实姓名,执行有编号改为名称
                for i in range(len(value['child'])):
                    if value['child'][i]['assignedTo']:
                        value['child'][i]['assignedTo'] = name_map[value['child'][i]['assignedTo']]

                test_task_dict[key] = value

            # 根据_type和_id条件进行筛选
            filter_data = {'type': _type, 'id': _id}
            test_task_select = self.get_modules_by_select(test_task_dict, filter_data)

            # 如果有搜索条件
            if filter_assignedTo or filter_status or filter_name:
                filter_data = {'name': filter_name, 'status': filter_status, 'lastRunner': filter_assignedTo}
                test_task_select = self.get_modules_by_select(test_task_select, filter_data)

            # return Response({'code': 1, 'msg': '获取成功', 'data': list(module_tree.values())})
            return Response({'code': 1, 'msg': '获取成功', 'data': {'teamCount':len(team),'list':list(test_task_select.values())}})
        except:
            print(traceback.format_exc())
            return Response({'code': 0, 'msg': '获取失败'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    # 根据条件进行筛选
    def get_modules_by_select(self, tree, filter_data):
        # 递归函数，用于遍历树并找到所有匹配status和name的模块及其所有子节点
        def traverse_and_filter(node):

            # 默认为True，不匹配直接返回
            judge = True
            for key, value in filter_data.items():
                judge = judge and (value is None or value in str(node[key]))
                if not judge:
                    break

            # 如果当前节点匹配status和name，则保留该节点及其所有子节点
            if judge:
                # 直接返回当前节点及其所有子节点
                return node.copy()

            # 如果当前节点不匹配，继续遍历子节点
            filtered_children = []
            for child_node in node.get('child', []):
                child_result = traverse_and_filter(child_node)
                if child_result:
                    filtered_children.append(child_result)

            # 如果子节点中有匹配的，则保留当前节点，包含所有子节点
            if filtered_children:
                filtered_node = node.copy()
                filtered_node['child'] = filtered_children
                return filtered_node

            # 如果没有匹配的子节点，返回None
            return None

        # 遍历整棵树，应用筛选条件
        filtered_tree = {}
        for mod_id, mod_node in tree.items():
            result = traverse_and_filter(mod_node)
            if result:
                filtered_tree[mod_id] = result

        return filtered_tree

#测试单详细数据
class DetailViewSet(viewsets.ViewSet):
    # queryset = ZtTask.objects
    # serializer_class = ZtTaskDetailSerializer

    def initial(self, request, *args, **kwargs):
        super(DetailViewSet, self).initial(request, *args, **kwargs)
        # 检查用户是否登录
        if not has_permission(request):
            # 如果用户未登录，抛出 AuthenticationFailed 异常
            raise AuthenticationFailed({'code': 0, 'msg': '未登录'})

    #格式化数据
    @timing_decorator
    def list(self, request, *args, **kwargs):
        '''
        根据项目id、功能模块id查询对应的开发任务
        '''
        try:
            #获取参数
            test_task_id = self.request.query_params.get('test_task_id', None)

            #如果project_id没有传
            if not test_task_id:
                return Response({'code': 0, 'msg': '没有携带测试单id'}, status=status.HTTP_400_BAD_REQUEST)

            test_task_id = test_task_id.split('-')[-1]

            test_task = ZtTestTask.objects.filter(deleted='0', id=test_task_id).select_related('execution')\
                .prefetch_related('testRun_task').distinct().first()

            # 未查询到
            if not test_task:
                return Response({'code': 0, 'msg': '该测试单不存在'})

            #团队人数
            team = set()

            # 转换关系
            status_map = {
                'doing': '进行中',
                'done': '已完成',
                'wait': '未开始',
                'blocked': '被阻塞'
            }

            type_map = {
                'integrate': '集成测试',
                'system': '系统测试',
                'acceptance': '验收测试',
                'performance': '性能测试',
                'safety': '安全测试',
                'dev':"构建单-研发环境",
                'test':'构建单-仿真环境',
                'prod':"构建单-生产环境",
                '':''
            }

            # 关联的测试单的用例
            testRuns = test_task.testRun_task.all()

            cases = []
            for testRun in testRuns:
                # 用例
                case = testRun.case
                if testRun.assignedTo:
                    team.add(testRun.assignedTo)

                #添加用例名
                cases.append('#{}{}'.format(case.id, case.title))

            # 获取成员用户名
            owner = test_task.owner
            members = test_task.members
            persons = set([owner] + members.split(','))

            # 收集所有用户名
            team |= persons

            # 修改状态
            test_task.status = status_map[test_task.status]

            # 使用指派事件和截止时间当做甘特图的起始时间

            if test_task.end is not None:

                # 判断给定的日期时间是否已经超期（即是否在当前日期时间之前）
                is_overdue = test_task.end < datetime.now(timezone.utc).date()
                if is_overdue and test_task.status != '已完成':
                    test_task.status = '超期告警'

            # 将测试类型转换为中文
            test_task_types = test_task.type.split(',')
            test_task.type = ';'.join([type_map[i] for i in test_task_types])

            # 获取执行版本
            execution = test_task.execution
            if execution:
                execution_name = '#{} {}'.format(execution.id, execution.name)
            else:
                execution_name = ''

            test_task_node = {
                "id": test_task.id,
                'name': test_task.name,
                'status': test_task.status,
                'pri': test_task.pri,
                'type': test_task.type,
                'cases': ';'.join(cases),
                'begin': '' if test_task.begin is None else test_task.begin.strftime('%Y-%m-%d'),
                'end': '' if test_task.end is None else test_task.end.strftime('%Y-%m-%d'),
                'members': persons,
                'execution': execution_name,
                'desc': test_task.desc
            }

            # 查询真实姓名
            name_map = {}
            users = ZtUser.objects.filter(account__in=team).values('account', 'realname')
            for user in users:
                name_map[user['account']] = user['realname']

            # 处理搜索结果为真实姓名
            persons_realname = [name_map[person] for person in persons]
            test_task_node['members'] = ';'.join(persons_realname)

            # return Response({'code': 1, 'msg': '获取成功', 'data': list(module_tree.values())})
            return Response({'code': 1, 'msg': '获取成功',
                             'data': {'teamCount': len(team), 'detail': test_task_node}})
        except:
            print(traceback.format_exc())
            return Response({'code': 0, 'msg': '获取失败'},status=status.HTTP_500_INTERNAL_SERVER_ERROR)